#include "header.h"
//file:class.cpp
namespace cvObjects
{
	EmptyObject::EmptyObject() :
		fn_updater( NULL ),
		fn_position( &EmptyObject::position_glb ),
		fn_rotate( &EmptyObject::rotate_glb ),
		fn_move( &EmptyObject::move_glb ),
		fn_turn( &EmptyObject::turn_glb ),
		fn_translate( &EmptyObject::translate_glb ),
		m_localpos( 0, 0 ),
		m_localrot( 0.0f ),
		m_position( 0, 0 ),
		m_rotation( 0 ) {}

	EmptyObject * EmptyObject::copy( cvMath::bitfield_t flags )
	{
		EmptyObject * obj = ObjectSubSystem::getInstance()->create<EmptyObject>();
		// TODO flags are not used..
		//obj->BaseObject::setParent(getParent());		// clone parenting data?
		obj->m_relativityflags		= m_relativityflags;
		obj->m_position		= m_position;
		obj->m_rotation		= m_rotation;
		obj->m_localpos		= m_localpos;
		obj->m_localrot		= m_localrot;
		return obj;
	}

// Object destruction:
	void EmptyObject::destroy()	{ delete this; }


//file:relativity.cpp
	int EmptyObject::objectType() const
	{
		return GAMEOBJECT_EMPTY;
	}

	void EmptyObject::setRelativity( cvMath::bitfield_t flags )
	{
		if( flags == OBJ_DEFAULT )	{ flags = OBJ_XYROT; }

		if( m_relativityflags != flags )
		{
			// check parent compability with this type.
			if( getParent()->objectType() != GAMEOBJECT_BASE )
			{
				// Dispatch flags.
				switch( cvMath::filterFlags( flags, OBJ_XYROT ) )
				{
					case OBJ_XYROT:	fn_position = &EmptyObject::position_local;
						fn_move = &EmptyObject::move_local;
						fn_translate = &EmptyObject::translate_local;
						fn_rotate = &EmptyObject::rotate_local;
						fn_turn = &EmptyObject::turn_local;
						fn_updater = &EmptyObject::xyrot_update;
						break;
					case OBJ_XY:	fn_position = &EmptyObject::position_local;
						fn_move = &EmptyObject::move_local;
						fn_translate = &EmptyObject::translate_local;
						fn_rotate = &EmptyObject::rotate_glb;
						fn_turn = &EmptyObject::turn_glb;
						fn_updater = &EmptyObject::xy_update;
						break;
					case OBJ_X:		fn_position = &EmptyObject::position_localx;
						fn_move = &EmptyObject::move_localx;
						fn_translate = &EmptyObject::translate_localx;
						fn_rotate = &EmptyObject::rotate_glb;
						fn_turn = &EmptyObject::turn_glb;
						fn_updater = &EmptyObject::x_update;
						break;
					case OBJ_Y:		fn_position = &EmptyObject::position_localy;
						fn_move = &EmptyObject::move_localy;
						fn_translate = &EmptyObject::translate_localy;
						fn_rotate = &EmptyObject::rotate_glb;
						fn_turn = &EmptyObject::turn_glb;
						fn_updater = &EmptyObject::y_update;
						break;
					case OBJ_ROTATION:	fn_position = &EmptyObject::position_glb;
						fn_move = &EmptyObject::move_glb;
						fn_translate = &EmptyObject::translate_glb;
						fn_rotate = &EmptyObject::rotate_local;
						fn_turn = &EmptyObject::turn_local;
						fn_updater = &EmptyObject::rot_update;
						break;
					default:		fn_position = &EmptyObject::position_glb;	// <no relativity>
						fn_move = &EmptyObject::move_glb;
						fn_translate = &EmptyObject::translate_glb;
						fn_rotate = &EmptyObject::rotate_glb;
						fn_turn = &EmptyObject::turn_glb;
						fn_updater = NULL;
				}
				cvMath::setFlag_on( m_relativityflags, cvMath::filterFlags( flags, OBJ_XYROT ) );
			}
		}

		BaseObject::setRelativity( flags );
	}

//file:update.cpp
// The main updater host
	void EmptyObject::updater()
	{
		// pull BaseObject attributes from parent
		BaseObject::updater();
		// If possible, pull EmptyObject attributes from parent.
		if( fn_updater )
		{
			( this->*fn_updater )();
		}
	}

// Relativity combinations:
	void EmptyObject::xyrot_update()	// pointted
	{
		const EmptyObject * obj = static_cast<EmptyObject*>( getParent() );
		float _cos, _sin;
		m_rotation = obj->m_rotation + m_localrot;
		_cos = cosf( -m_rotation );
		_sin = sinf( -m_rotation );
		m_position.x = obj->m_position.x + ( _cos * m_localpos.x + _sin * m_localpos.y );
		m_position.y = obj->m_position.y + ( -_sin * m_localpos.x + _cos * m_localpos.y );
		cvMath::setFlag_on( m_validrelatives, OBJ_XYROT );
	}
	void EmptyObject::xy_update()	// translated
	{
		m_position = static_cast<EmptyObject*>( getParent() )->m_position + m_localpos;
		cvMath::setFlag_on( m_validrelatives, OBJ_XY );
	}
// separate attributes:
	void EmptyObject::rot_update()  //rotated
	{
		m_rotation = static_cast<EmptyObject*>( getParent() )->m_rotation + m_localrot;
		cvMath::setFlag_on( m_validrelatives, OBJ_ROTATION );
	}
	void EmptyObject::x_update()    //x-translated
	{
		m_position.x = static_cast<EmptyObject*>( getParent() )->m_position.x + m_localpos.x;
		cvMath::setFlag_on( m_validrelatives, OBJ_X );
	}
	void EmptyObject::y_update()    //y-translated
	{
		m_position.y = static_cast<EmptyObject*>( getParent() )->m_position.y + m_localpos.y;
		cvMath::setFlag_on( m_validrelatives, OBJ_Y );
	}


//file:position.cpp
/// Setters, see EmptyObject::setRelativity()
	void EmptyObject::position( const cvMath::Vec2f & p )			{ ( this->*fn_position )( p ); }	// *public method*
	void EmptyObject::position_glb( const cvMath::Vec2f & p )		{ m_position = p; }
	void EmptyObject::position_local( const cvMath::Vec2f & p )	{ m_localpos = p; cvMath::setFlag_off( m_validrelatives, OBJ_XY ); }
	void EmptyObject::position_localx( const cvMath::Vec2f & p )
	{
		m_localpos.x = p.x;
		m_position.y = p.y;
		cvMath::setFlag_off( m_validrelatives, OBJ_X );
	}
	void EmptyObject::position_localy( const cvMath::Vec2f & p )
	{
		m_position.x = p.x;
		m_localpos.y = p.y;
		cvMath::setFlag_off( m_validrelatives, OBJ_Y );
	}

//file:angle.cpp >>>>
	void EmptyObject::rotate( float _angle )		{ ( this->*fn_rotate )( _angle * DEGREES_TO_RAD ); }	// *public method*
	void EmptyObject::rotate_glb( float _angle )	{ m_rotation = _angle; }
	void EmptyObject::rotate_local( float _angle )	{ m_localrot = _angle; cvMath::setFlag_off( m_validrelatives, OBJ_ROTATION ); }
//<<<
	void EmptyObject::move( float fwrd, float sidewrd )	{ ( this->*fn_move )( fwrd, sidewrd ); }	// *public method*
	void EmptyObject::move_glb( float fwrd, float sidewrd )
	{
		float _cos = cos( -m_rotation );
		float _sin = sin( -m_rotation );
		m_position.x += _cos * fwrd + _sin * sidewrd;
		m_position.y += -_sin * fwrd + _cos * sidewrd;
	}

	void EmptyObject::move_local( float fwrd, float sidewrd )
	{
		float _cos = cos( -m_rotation );
		float _sin = sin( -m_rotation );
		m_localpos.x += _cos * fwrd + _sin * sidewrd;
		m_localpos.y += -_sin * fwrd + _cos * sidewrd;
		cvMath::setFlag_off( m_validrelatives, OBJ_XY );
	}

	void EmptyObject::move_localx( float fwrd, float sidewrd )
	{
		float _cos = cos( -m_rotation );
		float _sin = sin( -m_rotation );
		m_localpos.x += _cos * fwrd + _sin * sidewrd;
		m_position.y += -_sin * fwrd + _cos * sidewrd;
		cvMath::setFlag_off( m_validrelatives, OBJ_X );
	}

	void EmptyObject::move_localy( float fwrd, float sidewrd )
	{
		float _cos = cos( -m_rotation );
		float _sin = sin( -m_rotation );
		m_position.x += _cos * fwrd + _sin * sidewrd;
		m_localpos.y += -_sin * fwrd + _cos * sidewrd;
		cvMath::setFlag_off( m_validrelatives, OBJ_X );
	}
//file:angle.cpp >>>>
	void EmptyObject::turn( float delta )		{ ( this->*fn_turn )( delta * DEGREES_TO_RAD ); }	// *public method*
	void EmptyObject::turn_glb( float delta )	{ m_rotation += delta; }
	void EmptyObject::turn_local( float delta )	{ m_localrot += delta; cvMath::setFlag_off( m_validrelatives, OBJ_ROTATION ); }
//<<<
	void EmptyObject::translate( const cvMath::Vec2f & p )			{ ( this->*fn_translate )( p ); }	// *public method*
	void EmptyObject::translate_glb( const cvMath::Vec2f & p )		{ m_position += p; }
	void EmptyObject::translate_local( const cvMath::Vec2f & p )	{ m_localpos += p; cvMath::setFlag_off( m_validrelatives, OBJ_XY ); }
	void EmptyObject::translate_localx( const cvMath::Vec2f & p )
	{
		m_localpos.x += p.x;
		m_position.y += p.y;
		cvMath::setFlag_off( m_validrelatives, OBJ_X );
	}
	void EmptyObject::translate_localy( const cvMath::Vec2f & p )
	{
		m_position.x += p.x;
		m_localpos.y += p.y;
		cvMath::setFlag_off( m_validrelatives, OBJ_Y );
	}

/// Getters
	const cvMath::Vec2f & EmptyObject::position()
	{
		// We must do recurssive update on the objects position
		update_linear();
		return m_position;
	}

//file:angle.cpp
	float EmptyObject::angle()
	{
		update_linear();
		return m_rotation * RAD_TO_DEGREES;
	}

	const cvMath::Vec2f & EmptyObject::localPosition() const	{ return m_localpos; }

	float EmptyObject::localAngle() const	{ return m_localrot; }
};
